﻿namespace NumericalData.SolvationMethods
open System
open NumericalData
open System.Diagnostics
open NumericalData.Systems
open NumericalData.Exceptions
open NumericalData.Attributes
open NumericalData.SolvationMethods
open NumericalData.SolvationMethods.Async

[<SolvationMethodAnalysisWorkName("Simple Explicit Method")>]
type SimpleExplicitSolvationMethod = 
    class
        inherit TraceableIterationMethod
        new() = {inherit TraceableIterationMethod()}
        /// <summary>
        /// Solve SLAE using simple explicit method Xn+1 = (E - TnA)Xn + TnH
        /// <param name="sys">System to be solved</param>
        /// <param name="accur"> accurcy - simply iteration method parameter</param>
        /// <exception cref="SLAEInitialMatrixCantBeSolvedException">Matrix can't be solved with this method</exception>
        /// </summary>
        override x.Solve system accur startIsZero maxIterations = 
            
            let matrixRate = (Rates.FrobeniusRate system.InitialMatrix)
               
            let Tau =  1./(matrixRate)

            let E = MatrixGenerators<SquareMatrix>.IdentityMatrix system.InitialMatrix.Dimention

            let bMatr = (E - Tau*system.InitialMatrix)
            let bVec  = (Tau*system.InitialVector)

            let (vec,iters) = x.Iterate accur startIsZero maxIterations bMatr bVec

            x.FormResult system vec iters accur 

        interface IAsyncSolvable<DiagnosticsAnswer> with 
            member x.AsyncSolve system accur startIsZero maxIterations asyncSuccess asyncFail asyncCancel = 
                let loppedSolveMethod = x.TraceSolve system accur startIsZero
                AsyncSolveFactory.Generate<int,DiagnosticsAnswer> loppedSolveMethod maxIterations asyncSuccess asyncFail asyncCancel
       
        member x.AsyncSolve  = (x :> IAsyncSolvable<DiagnosticsAnswer>).AsyncSolve
    end
